package cn.ac.ict.fpevaluation.utils;

import cn.ac.ict.fpevaluation.bean.APBean;
import cn.ac.ict.fpevaluation.bean.AtomTrajectoryBean;
import cn.ac.ict.fpevaluation.fastdtw.dtw.TimeWarpInfo;
import cn.ac.ict.fpevaluation.fastdtw.test.FastDTWTest;
import cn.ac.ict.fpevaluation.fastdtw.timeseries.TimeSeriesPoint;
import javafx.scene.effect.GaussianBlur;

import java.util.*;

/**
 * Created by wuyouxiong on 2017/3/3.
 */
public class WifiHelper {

    private static final double DEFAULT_MIN_WIFI_RSS = -100;


    /**
     * @param ap 某一时刻采集到的所有ap点的值
     */
    public static void sortByMac(List<APBean> ap) {

        Collections.sort(ap, new Comparator<APBean>() {
            @Override
            public int compare(APBean o1, APBean o2) {
                return o1.getMAC().compareTo(o2.getMAC());
            }
        });
    }

    // 把 list2 = list2 ∪ (list2 - list1) 剩余的集合
    public static void remedyRssByMac(List<APBean> list1, List<APBean> list2) {

        Set<String> macs = new HashSet<>();
        list1.forEach(item -> macs.add(item.getMAC()));
        list2.forEach(item -> macs.add(item.getMAC()));

        Iterator<String> iterator = macs.iterator();
        Random random = new Random();
        while (iterator.hasNext()) {
            String mac = iterator.next();
            boolean exist = false;
            for (APBean item : list1) {
                if (item.getMAC().equals(mac)) {
                    item.setRSS(item.getRSS());
                    exist = true;
                    break;
                }
            }
            if (!exist) list1.add(new APBean(-90, mac, "SSID IS EMPTY"));
            exist = false;
            for (APBean item : list2) {
                if (item.getMAC().equals(mac)) {
                    item.setRSS(item.getRSS());
                    exist = true;
                    break;
                }
            }
            if (!exist) list2.add(new APBean(-90, mac, "SSID IS EMPTY"));
        }

    }

    /**
     * 融合同一步子的Ap
     *
     * @param list1
     * @param list2
     */
    public static List<APBean> fusionRssByMac(List<APBean> list1, List<APBean> list2) {
        if (list1 == null) return list2;
        if (list2 == null) return list1;
        remedyRssByMac(list1, list2);
        List<APBean> res = new ArrayList<>();
        for (int i = 0; i < list1.size() && i < list2.size(); i++) {
            if (list1.get(i).getMAC().equals(list2.get(i).getMAC())) {
                APBean item = new APBean((list1.get(i).getRSS() + list2.get(i).getRSS()) / 2, list1.get(i).getMAC(), list1.get(i).getSSID());
                res.add(item);
            }
        }
        return res;
    }

    public static void firstDtw() {
        List<AtomTrajectoryBean> atomTrajectories = DataOperationToDiskUtils.getOriginalData();
        int count = 0;
        double sum = 0;
        for (int i = 0; i < atomTrajectories.size() - 1; i++) {
            for (int j = i + 1; j < atomTrajectories.size(); j++) {
                count++;
                double distance = calDtw(atomTrajectories.get(i).getAps(), atomTrajectories.get(j).getAps());
                sum += distance;
                System.out.println("两条轨迹之间的DTW distance为: " + distance);

            }
        }

        System.out.printf("平均DTW Distance为: " + sum / count);
    }

    public static double calDtw(List<List<APBean>> list1, List<List<APBean>> list2) {
        double[][] dtw = new double[list1.size() + 1][list2.size() + 1];
        int n = list1.size();
        int m = list2.size();
        for (int i = 1; i < n; i++) {
            dtw[i][0] = Integer.MAX_VALUE;
        }

        for (int i = 1; i < m; i++) {
            dtw[0][i] = Integer.MAX_VALUE;
        }
        dtw[0][0] = 0;

        for (int i = 1; i < n; i++) {
            for (int j = 1; j < m; j++) {
//                double cost = subDtwDistance(list1.get(i), list2.get(j));
                double cost = euclideanDistanceAfterRemedy(list1.get(i), list2.get(j));
                //System.out.printf("cost : " + cost + "\n");
                dtw[i][j] = cost + Math.min(dtw[i - 1][j - 1], Math.min(dtw[i - 1][j], dtw[i][j - 1]));
            }
        }

        return dtw[n - 1][m - 1];

    }

    public static double euclideanDistanceAfterRemedy(List<APBean> l1, List<APBean> l2) {
        List<APBean> list1 = new ArrayList<>(l1);
        List<APBean> list2 = new ArrayList<>(l2);
        WifiHelper.remedyRssByMac(list1, list2);
        WifiHelper.remedyRssByMac(list2, list1);
        WifiHelper.sortByMac(list1);
        WifiHelper.sortByMac(list2);
        return euclideanDistance(list1, list2);
    }

    public static double euclideanDistance(List<APBean> list1, List<APBean> list2) {
        int distance = 0;
        for (int i = 0; i < list1.size(); i++) {
            APBean aBean = list1.get(i);

            APBean bBean = list2.get(i);
            if (aBean.getMAC().equals(bBean.getMAC())) {
                distance += Math.pow(aBean.getRSS() - bBean.getRSS(), 2.0);
                i++;
            }

        }
        return Math.sqrt(distance);
    }


    public static double subDtwDistance(List<APBean> list1, List<APBean> list2) {
        WifiHelper.sortByMac(list1);
        WifiHelper.sortByMac(list2);
        TimeWarpInfo t = new FastDTWTest().calDistance(gettsArray(list1), gettsArray(list2), 3);

        return t.getDistance();
    }

    public static ArrayList<Object> gettsArray(List<?> samplelist) {
        ArrayList<Object> tsArray = new ArrayList<Object>();

        for (int i = 0; i < samplelist.size(); i++) {
            final ArrayList<Double> currentLineValues = new ArrayList<Double>();
            Object sample = samplelist.get(i);
            if (sample instanceof APBean) {
                currentLineValues.add(((APBean) sample).getRSS());
            }

            final TimeSeriesPoint readings = new TimeSeriesPoint(currentLineValues.subList(0, currentLineValues.size()));

            tsArray.add(readings);
        }
        return tsArray;
    }

}
